////////////////////////////////////////////////
// DESCRIPTION:
//    Implementation of Type safe threads for class methods
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//

#include <Windows.h>
//#include <pkfuncs.h>
#include <FusionWare\Win32.h>

using namespace FusionWare::Threads;

// Stub function to transition from 
// OS defined API to the Functor 
DWORD Thread::ThreadStub( Thread* pThread)
{
    return pThread->ThreadFunc();
}

////////////////////////////////////////////////
// Description:
//   Starts a the thread
//
// Input:
//    Func        - Pointer to Thread function stub
//    Priority    - Priority of the thread
//    PriExt      - true if CE extended priority (CeSetThreadPriority)
//    flags       - 0 or CREATE_SUSPENDED
//    StackSize   - Stack Size (must be 0 for CE)
//
// Remarks:
//    Wrapper around CreateThread that allows for
//    setting the threads priority at creation
//
bool Thread::Start(ThreadFunction Func,
                   int Priority,
                   bool PriExt,
                   DWORD flags,
                   DWORD StackSize)
{
    DWORD ID;

    this->ThreadFunc = Func;

    operator=( CreateThread( NULL
                           , StackSize
                           , reinterpret_cast<LPTHREAD_START_ROUTINE>(&ThreadStub)
                           , this
                           , CREATE_SUSPENDED
                           , &ID
                           )
             );

    if(NULL==this->Win32Handle)
        return false;
    
    // NOTE:
    //   At this point the thread is created so ALL 
    //   FAIL cases *MUST* Terminate it and close
    //   the handle.
    
    // Now set the priority of the thread
    if(!SetPriority(Priority,PriExt))
        goto TermExit;

    if(CREATE_SUSPENDED!=flags)
    {
        if(0xFFFFFFFF==Resume())
            goto TermExit;
    }
    return true;

// exit point for failures to kill the created but still suspended thread
TermExit:
   TerminateThread(this->Win32Handle,-1);
   Close();
   return FALSE;
}

#ifdef UNDER_CE

////////////////////////////////////////////////
// Description:
//    Stops the IST in preperation for device shutdown
//
// Returns:
//    BOOL - TRUE if the thread was stopped FALSE if not
//
// Comments:
//    Overloads base class implementation of Stop 
//    to handle special cases of IST threads where
//    the interrupt event must be set to pop the IST
//    out of it's infinite wait.
//
bool IntSvcThread::Stop(DWORD timeout/*=INFINITE*/)
{
    bool retVal = true;
    
    if(!this->hIntEvent)
    {
        StoppableThread::Stop(0);  // Set the Abort flag
        
        // Set Priority to same as this thread so no priority issues
        // get in the way of stopping the thread
        SetPriority(CeGetThreadPriority(GetCurrentThread()), true);
        this->hIntEvent.Set();           // Pop it out of the wait for event
        retVal=WaitForExit(timeout);     // Wait as indicated by callee
        InterruptDone();                 // Clear any pending Interrupts
        InterruptDisable(this->SysIntr); // Disable the interrupt with the OS
    }
    
    return retVal;
}

////////////////////////////////////////////////
// Description:
//    Waits for the IST event
//
// Returns:
//    IST_ABORT     - If thread should stop looping
//    IST_INTERRUPT - Thread should process the interrupt
//    IST_TIMEOUT   - Timeout for the wait
//
// Remarks:
//    Used inside the IST to wait for the interrupt
//    event to occur.
//
IntSvcThread::ISTWait IntSvcThread::WaitForInterrupt(UINT32 TimeOut /*= INFINITE*/)
{
    ISTWait retVal = IST_ABORT;

    if(!GetAbortFlag())
    {
        DWORD waitResult = this->hIntEvent.Wait(TimeOut);
        switch(waitResult)
        {
        case WAIT_OBJECT_0:
            retVal = IST_INTERRUPT;
            break;

        case WAIT_TIMEOUT:
            retVal = IST_TIMEOUT;
            break;

        default:
            retVal = IST_ABORT;
            break;
        };
    }

    // test for abort again after popping out of wait!
    // abort flag wins out over everything. 
    return GetAbortFlag() ? IST_ABORT : retVal;
}

#endif //UNDER_CE

